package com.jee.ssm.modules.billRecord.app;

import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.jee.ssm.common.config.Logger;
import com.jee.ssm.common.config.ShopInfo;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.jee.ssm.common.utils.CalculateUtils;
import com.jee.ssm.common.utils.QrCodeUtil;
import com.jee.ssm.common.utils.TokenUtils;
import com.jee.ssm.common.utils.UUIDFactory;
import com.jee.ssm.common.utils.wechat.WXPay;
import com.jee.ssm.common.utils.wechat.XMLUtil;
import com.jee.ssm.common.utils.wechat.PaymaxConfig;
import com.jee.ssm.common.utils.wechat.RandCharsUtils;
import com.jee.ssm.common.utils.wechat.Unifiedorder;
import com.jee.ssm.model.BillRecord;
import com.jee.ssm.model.User;
import com.jee.ssm.model.json.Tip;
import com.jee.ssm.modules.billRecord.services.BillRecordService;
import com.jee.ssm.modules.user.services.UserService;

/**
* 订单记录管理 客户端 Controller
* @author GaoXiang
* @version 1.0
*/
@Controller
@RequestMapping("/app/billRecord")
public class AppBillRecordController {

    @RequestMapping(value = "/findBillRecordByUserId", method = RequestMethod.GET)
    @ResponseBody
    public Tip findBillRecordByUserId(long timestamp, String token, String userId) {
    	Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
        	List<BillRecord> list = billRecordService.findByUserId(userId);
        	tip = new Tip(list);
        }
        return tip;
    }
    
    @RequestMapping(value = "/rechargeByAlipay", method = RequestMethod.GET)
    @ResponseBody
    public Tip rechargeByAlipay(long timestamp, String token, String userId, String amount) {
        Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
            User user = userService.selectById(userId);
            if(user != null) {
                BigDecimal money = CalculateUtils.null2Decimal(amount);
                if(money.compareTo(BigDecimal.valueOf(0.01)) != -1) {
                    String number = UUIDFactory.getBillNUmber(user.getPhone());
                    BillRecord billRecord = new BillRecord(UUIDFactory.getStringId(), number, money, new Date(), "余额充值", "+", 0, 1, 1, null, "余额充值", userId, user.getUserName(), user.getPhone(), user.getName(), user.getIdNumber(), "2",new Date(),new Date(),0,"充值余额无车牌");

                    //实例化客户端
                    AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", ShopInfo.APP_ID, ShopInfo.PRIVATE_KEY, "json", "utf-8", ShopInfo.PUBLIC_KEY, "RSA2");
                    //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
                    AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
                    //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
                    AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                    model.setBody("");
                    model.setSubject("余额充值");
                    model.setOutTradeNo(number);
                    model.setTimeoutExpress("30m");
                    model.setTotalAmount(String.valueOf(money));
                    model.setProductCode("QUICK_MSECURITY_PAY");
                    request.setBizModel(model);
                    request.setNotifyUrl(ShopInfo.ALI_RECHARGE_NOTIFYURL);
                    try {
                        //这里和普通的接口调用不同，使用的是sdkExecute
                        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
                        //就是orderString 可以直接给客户端请求，无需再做处理。
                        billRecordService.insert(billRecord);
                        tip.setData(response.getBody());
                    } catch (AlipayApiException e) {
                        e.printStackTrace();
                        tip = new Tip(2, "充值数据异常");
                    } catch (Exception e) {
                        tip = new Tip(3, "系统异常，请刷新重试");
                    }
                } else {
                    tip = new Tip(4, "请输入正确的充值金额");
                }

            } else {
                tip = new Tip(1, "用户信息失效，请重新登录");
            }
        }
        return tip;
    }

    @SuppressWarnings("rawtypes")
	@RequestMapping(value = "/alipayCallBack575872E59B8F4499BC18867904071FC5")
    @ResponseBody
    public String alipayCallBack575872E59B8F4499BC18867904071FC5(HttpServletRequest request) {
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
        String number = params.get("out_trade_no");
        Logger.info("回调订单号：" + number);
        String result = null;
        try {
            boolean flag = AlipaySignature.rsaCheckV1(params, ShopInfo.PUBLIC_KEY, "utf-8","RSA2");
            if(flag) {
                BillRecord billRecord = billRecordService.findByNumber(number);
                if(billRecord != null) {
                    String total_amount = params.get("total_amount");
                    String receipt_amount = params.get("receipt_amount");
                    String invoice_amount = params.get("invoice_amount");
                    String buyer_pay_amount = params.get("buyer_pay_amount");
                    Logger.info("订单金额：" + total_amount);
                    Logger.info("实收金额：" + receipt_amount);
                    Logger.info("开票金额：" + invoice_amount);
                    Logger.info("付款金额：" + buyer_pay_amount);
                    if(billRecord.getType() == 1) {
                    	//支付宝充值成功
                    	billRecordService.updateFinishStatus(billRecord);
                    } else if(billRecord.getType() == 3) {
                    	//支付宝支付停车账单成功
                    	billRecordService.updateHikBill(billRecord, 2);
                    }
                    
                    result = "success";
                } else {
                    Logger.info("未查找到编号为：" + number + "的订单");
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
            Logger.info("修改订单编号为：" + number + "状态失败");
        }
        return result;
    }

    @RequestMapping(value = "/rechargeByWXpay", method = RequestMethod.GET)
    @ResponseBody
    public Tip rechargeByWXpay(long timestamp, String token, String userId, String amount, HttpServletRequest request) {
        Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
            User user = userService.selectById(userId);
            if(user != null) {
                BigDecimal money = CalculateUtils.null2Decimal(amount);
                if(money.compareTo(BigDecimal.valueOf(0.01)) != -1) {
                    String number = UUIDFactory.getBillNUmber(user.getPhone());
                    BillRecord billRecord = new BillRecord(UUIDFactory.getStringId(), number, money, new Date(), "余额充值", "+", 0, 1, 1, null, "余额充值", userId, user.getUserName(), user.getPhone(), user.getName(), user.getIdNumber(), "3",new Date(),new Date(),0,"充值余额无车牌");
                    
                    PaymaxConfig config = new PaymaxConfig(ShopInfo.WX_APPID, ShopInfo.WX_MCHID, ShopInfo.WX_KEY, ShopInfo.WX_RECHARGE_NOTIFYURL, ShopInfo.WX_TRADETYPE_APP, ShopInfo.WX_URL, ShopInfo.POST);
                    
                    Unifiedorder unifiedorder = new Unifiedorder();
                    unifiedorder.setAppid(config.getAppId());
            		unifiedorder.setMch_id(config.getMchId());
            		unifiedorder.setNonce_str(RandCharsUtils.getRandomString(16));
            		unifiedorder.setBody(billRecord.getContent());
            		unifiedorder.setDetail(billRecord.getIntro());
            		unifiedorder.setAttach("");
            		unifiedorder.setOut_trade_no(number);
            		unifiedorder.setTotal_fee(CalculateUtils.multiply(money, 100).intValue());
            		unifiedorder.setSpbill_create_ip(request.getRemoteAddr());
            		unifiedorder.setTime_start(RandCharsUtils.timeStart());
            		unifiedorder.setTime_expire(RandCharsUtils.timeExpire());
            		unifiedorder.setNotify_url(config.getNotifyUrl());
            		unifiedorder.setTrade_type(config.getTradeType());
                	tip = new WXPay().payByApp(unifiedorder, config);
                	if(tip.getSuccess()) {
                		try {
        					billRecordService.insert(billRecord);
        				} catch (Exception e) {
        					e.printStackTrace();
        					Logger.info("编号为：" + number + "的订单保存失败");
        				}
                	}
                } else {
                    tip = new Tip(4, "请输入正确的充值金额");
                }

            } else {
                tip = new Tip(1, "用户信息失效，请重新登录");
            }
        }
        return tip;
    }
    
    @RequestMapping(value = "/rechargeOrderWXProgramPay", method = RequestMethod.GET)
    @ResponseBody
    public Tip rechargeOrderWXProgramPay(long timestamp, String token, String userId, String amount, String openId, HttpServletRequest request) {
        Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
            User user = userService.selectById(userId);
            if(user != null) {
                BigDecimal money = CalculateUtils.null2Decimal(amount);
                if(money.compareTo(BigDecimal.valueOf(0.01)) != -1) {
                    String number = UUIDFactory.getBillNUmber(user.getPhone());
                    BillRecord billRecord = new BillRecord(UUIDFactory.getStringId(), number, money, new Date(), "余额充值", "+", 0, 1, 1, null, "余额充值", userId, user.getUserName(), user.getPhone(), user.getName(), user.getIdNumber(), "7",new Date(),new Date(),0,"余额提现无车牌");
                    PaymaxConfig config = new PaymaxConfig(ShopInfo.WX_PROGRAM_ID, ShopInfo.WX_PROGRAM_MECHID, ShopInfo.WX_PROGRAM_KEY, ShopInfo.WX_RECHARGE_NOTIFYURL, ShopInfo.WX_TRADETYPE_PROGRAM, ShopInfo.WX_URL, ShopInfo.POST);
                    Unifiedorder unifiedorder = new Unifiedorder();
                    unifiedorder.setAppid(config.getAppId());
            		unifiedorder.setMch_id(config.getMchId());
            		unifiedorder.setNonce_str(RandCharsUtils.getRandomString(16));
            		unifiedorder.setBody(billRecord.getContent());
            		unifiedorder.setDetail(billRecord.getIntro());
            		unifiedorder.setAttach("");
            		unifiedorder.setOut_trade_no(number);
            		unifiedorder.setTotal_fee(CalculateUtils.multiply(money, 100).intValue());
            		unifiedorder.setSpbill_create_ip(request.getRemoteAddr());
            		unifiedorder.setTime_start(RandCharsUtils.timeStart());
            		unifiedorder.setTime_expire(RandCharsUtils.timeExpire());
            		unifiedorder.setNotify_url(config.getNotifyUrl());
            		unifiedorder.setTrade_type(config.getTradeType());
                    unifiedorder.setOpenid(openId);
                	tip = new WXPay().payByProgramApp(unifiedorder, config);
                	if(tip.getSuccess()) {
                		try {
        					billRecordService.insert(billRecord);
        				} catch (Exception e) {
        					e.printStackTrace();
        					Logger.info("编号为：" + number + "的订单保存失败");
        				}
                	}
                } else {
                    tip = new Tip(4, "请输入正确的充值金额");
                }

            } else {
                tip = new Tip(1, "用户信息失效，请重新登录");
            }
        }
        return tip;
    }
    
    @RequestMapping(value = "/getWXpayCode", method = RequestMethod.GET)
    public String getWXpayCode(String userId, String amount, HttpServletRequest request, Model model) {
    	Tip tip = new Tip();
        User user = userService.selectById(userId);
        if(user != null) {
            BigDecimal money = CalculateUtils.null2Decimal(amount);
            if(money.compareTo(BigDecimal.valueOf(0.01)) != -1) {
                String number = UUIDFactory.getBillNUmber(user.getPhone());
                BillRecord billRecord = new BillRecord(UUIDFactory.getStringId(), number, money, new Date(), "余额充值", "+", 0, 1, 1, null, "余额充值", userId, user.getUserName(), user.getPhone(), user.getName(), user.getIdNumber(), "6",new Date(),new Date(),0,"余额充值无车牌");
                
                PaymaxConfig config = new PaymaxConfig(ShopInfo.WX_APPID, ShopInfo.WX_MCHID, ShopInfo.WX_KEY, ShopInfo.WX_RECHARGE_NOTIFYURL, ShopInfo.WX_TRADETYPE_WEB, ShopInfo.WX_URL, ShopInfo.POST);
                
                Unifiedorder unifiedorder = new Unifiedorder();
                unifiedorder.setAppid(config.getAppId());
        		unifiedorder.setMch_id(config.getMchId());
        		unifiedorder.setNonce_str(RandCharsUtils.getRandomString(16));
        		unifiedorder.setBody(billRecord.getContent());
        		unifiedorder.setDetail(billRecord.getIntro());
        		unifiedorder.setAttach("");
        		unifiedorder.setOut_trade_no(number);
        		unifiedorder.setTotal_fee(CalculateUtils.multiply(money, 100).intValue());
        		unifiedorder.setSpbill_create_ip("127.0.0.1");
        		unifiedorder.setTime_start(RandCharsUtils.timeStart());
        		unifiedorder.setTime_expire(RandCharsUtils.timeExpire());
        		unifiedorder.setNotify_url(config.getNotifyUrl());
        		unifiedorder.setTrade_type(config.getTradeType());
                
            	tip = new WXPay().payByCode(unifiedorder, config);
            	if(tip.getSuccess()) {
            		try {
    					billRecordService.insert(billRecord);
    					String url = "/images/code/";
    					String path = request.getServletContext().getRealPath(url);
    					String name = number + ".jpg";
    	        	    QrCodeUtil.createQrCode(tip.getMessage(), path, name);
    	        	    tip = new Tip(url + name);
    				} catch (Exception e) {
    					e.printStackTrace();
    					Logger.info("编号为：" + number + "的订单保存失败");
    				}
            	}
            } else {
                tip = new Tip(4, "请输入正确的充值金额");
            }

        } else {
            tip = new Tip(1, "用户信息失效，请重新登录");
        }
        model.addAttribute("tip", tip);
        return "manager/wx-code";
    }
    
    @SuppressWarnings("rawtypes")
	public void test(Map<String, Object> parameters) {
        Set<Entry<String, Object>> set = parameters.entrySet();
        Map.Entry[] entries = (Map.Entry[])set.toArray(new Map.Entry[set.size()]);
        for (int i=0;i<entries.length;i++){
            System.out.println(entries[i].getKey().toString() + "：" + entries[i].getValue().toString());
        }
    }

    /** 
     * 微信支付通知地址 
     * 
     * @param request 
     * @return 
     * @throws IOException 
     */  
    @SuppressWarnings("unchecked")
	@RequestMapping(value = "/WXpayCallBackF0D56C07947C4D3E874EED3DCCDA6DF7",method=RequestMethod.POST)
    @ResponseBody
    public String WXpayCallBackF0D56C07947C4D3E874EED3DCCDA6DF7(HttpServletRequest request) throws IOException {
        BufferedReader reader = request.getReader();
        String line = "";
        StringBuffer inputString = new StringBuffer();
        String result = null;
        try {
        	while ((line = reader.readLine()) != null) {
        		inputString.append(line);
        	}
	        request.getReader().close();
	        Map<String, String> restmap = XMLUtil.doXMLParse(inputString.toString());
	        if("SUCCESS".equals(restmap.get("result_code"))){
	        	String out_trade_no = restmap.get("out_trade_no");
	        	BillRecord billRecord = billRecordService.findByNumber(out_trade_no);
                if(billRecord != null) {
                	if(billRecord.getType() == 1) {
                    	//微信充值成功
                    	billRecordService.updateFinishStatus(billRecord);
                    } else if(billRecord.getType() == 3) {
                    	//微信支付停车账单成功
                    	billRecordService.updateHikBill(billRecord, 3);
                    }
                    result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                } else {
                    Logger.info("未查找到编号为：" + out_trade_no + "的订单");
                }
	        }
        } catch(Exception e) {
            e.printStackTrace();
        }
    	return result;
    }
    
    /**
     * 计算手续费
     * @param userId 用户标识
     * @param amount 提现 金额
     * @return 手续费
     */
    @RequestMapping(value = "/calculateRealAmount", method = RequestMethod.GET)
    @ResponseBody
    public Tip calculateRealAmount(long timestamp, String token, String userId, String amount) {
    	Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
        	User user = userService.selectById(userId);
        	if(user != null) {
        		BigDecimal money = CalculateUtils.null2Decimal(amount);
        		if(money.compareTo(BigDecimal.valueOf(1)) != -1) {
        			if(user.getWalletBalance().compareTo(money) != -1) {
                    	BigDecimal a = CalculateUtils.null2Decimal(CalculateUtils.multiply(money, 0.01));
                    	tip = new Tip(a);
                    } else {
                		tip = new Tip(3, "余额不足");
                	}
        		} else {
        			tip = new Tip(2, "提现金额必须大于1元");
        		}
        	} else {
        		tip = new Tip(1, "用户信息失效，请重新登录");
        	}
        }
        return tip;
    }
    
    /**
     * 提现到支付宝
     * @param userId 用户标识
     * @param account 支付宝账户
     * @param amount 提现金额
     * @param name 账户姓名
     * @return 支付宝返回结果
     */
    @RequestMapping(value = "/transferToAccountByAlipay", method = RequestMethod.GET)
    @ResponseBody
    public Tip transferToAccountByAlipay(long timestamp, String token, String userId, String account, String amount, String name) {
    	Tip tip = TokenUtils.verifyToken(timestamp, token);
        if(tip.getSuccess()) {
        	User user = userService.selectById(userId);
        	if(user != null) {
        		BigDecimal money = CalculateUtils.null2Decimal(amount);
                if(money.compareTo(BigDecimal.valueOf(1)) != -1) {
                	if(user.getWalletBalance().compareTo(money) != -1) {
                		BigDecimal transferMoney = CalculateUtils.null2Decimal(CalculateUtils.subtract(money, CalculateUtils.multiply(money, 0.01)));
                		String number = UUIDFactory.getBillNUmber(user.getPhone());
                		AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", ShopInfo.APP_ID, ShopInfo.PRIVATE_KEY, "JSON", "utf-8", ShopInfo.PUBLIC_KEY, "RSA2");
                    	AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
                    	String payName = "";
                    	if(name != null && !"".equals(name)) {
                    		payName = "\"payee_real_name\":\"" + name + "\",";
                    	}
                    	request.setBizContent("{" +
                    	"\"out_biz_no\":\"" + number + "\"," +
                    	"\"payee_type\":\"ALIPAY_LOGONID\"," +
                    	"\"payee_account\":\"" + account + "\"," +
                    	"\"amount\":\"" + String.valueOf(transferMoney) + "\"," +
                    	"\"payer_show_name\":\"山东慧若电子商务有限公司\"," +
                    	payName +
                    	"\"remark\":\"约慧夏都余额提现\"" +
                    	"}");
            			try {
            				AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
            				
            				if(response.isSuccess()){
            					System.out.println(response.getCode());
            					System.out.println(response.getMsg());
            					System.out.println(response.getOrderId());
            					System.out.println(response.getOutBizNo());
            					System.out.println(response.getPayDate());
            					System.out.println(response.getSubCode());
            					System.out.println(response.getSubMsg());
            					System.out.println(response.getBody());
            					System.out.println(response.getParams());
            		        	System.out.println("调用成功");
            		        	BillRecord billRecord = new BillRecord(UUIDFactory.getStringId(), number, money, new Date(), "余额提现", "-", 1, 1, 0, account, "余额" + amount + "元提现到支付宝账户：" + account + "，实际到账金额：" + transferMoney + "元", userId, user.getUserName(), user.getPhone(), user.getName(), user.getIdNumber(), "0",new Date(),new Date(),0,"余额提现无车牌");
            		        	billRecordService.insert(billRecord);
            		        	user.setWalletBalance(CalculateUtils.subtract(user.getWalletBalance(), money));
            		        	userService.updateById(user);
            		        	tip = new Tip("提现成功");
            				} else {
            		        	tip = new Tip(5, "支付宝调用失败");
            		        }
            			} catch (AlipayApiException e) {
            				e.printStackTrace();
            				tip = new Tip(4, "支付宝系统异常");
            			} catch (Exception e) {
            				tip = new Tip("提现成功，保存账单失败");
							e.printStackTrace();
						}
                	} else {
                		tip = new Tip(3, "余额不足");
                	}
                } else {
                	tip = new Tip(2, "提现金额必须大于1元");
                }
        		
        	} else {
        		tip = new Tip(1, "用户信息失效，请重新登录");
        	}
        }
        return tip;
    }


    //---------------------------- property -------------------------------

    @Resource
    private BillRecordService billRecordService;

    @Resource
    private UserService userService;

}
